using System;
using System.Collections.Generic;
using System.Text;
using RikMigrations.Providers;
using System.ComponentModel;

namespace RikMigrations
{
	public interface IMigration
	{
		void Up(DbProvider db);
		void Down(DbProvider db);
	}

    [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true)]
	public class MigrationAttribute : Attribute, IComparable<MigrationAttribute>
	{
        /// <summary>
        /// Only use this on a class not on an Assembly Attribute
        /// </summary>
        /// <param name="version"></param>
        public MigrationAttribute(int version)
        {
            this.version = version;
        }

		public MigrationAttribute(Type type, int version)
		{
			this.type = type;
			this.version = version;
		}

		public MigrationAttribute(Type type, int version, string moduleName)
		{
			this.type = type;
			this.version = version;
			this.moduleName = moduleName;
		}

		#region Properties
		private Type type;
		public Type Type
		{
			get { return type; }
            set { type = value; }
		}

		private int version;
		public int Version
		{
			get { return version; }
		}

		private string moduleName;
		public string ModuleName
		{
			get { return moduleName ?? MigrationManager.DefaultModuleName; }
			set { moduleName = value; }
		}
		#endregion

		public void Up(DbProvider db)
		{
			db.CreateTransaction();
			try
			{
				IMigration migration = Activator.CreateInstance(Type) as IMigration;
				if (migration == null)
					throw new InvalidOperationException("Migration type does not implement IMigration - " + Type.Name);
				Log.WriteLine("Upgrading to version {0} (Module: {1})", Version, ModuleName);
				migration.Up(db);

				db.SetModuleVersion(ModuleName, Version);
				db.CommitTransaction();
			}
			catch
			{
				db.RollbackTransaction();
				throw;
			}
		}

		public void Down(DbProvider db)
		{
			db.CreateTransaction();
			try
			{
				IMigration migration = Activator.CreateInstance(Type) as IMigration;
				if (migration == null)
					throw new InvalidOperationException("Migration type does not implement IMigration - " + Type.Name);
				Log.WriteLine("Downgrading from version {0} (Module: {1})", Version, ModuleName);
				migration.Down(db);

				db.SetModuleVersion(ModuleName, Version - 1);
				db.CommitTransaction();
			}
			catch
			{
				db.RollbackTransaction();
				throw;
			}
		}

		#region IComparable<MigrationAttribute> Members
		public int CompareTo(MigrationAttribute that)
		{
			return version.CompareTo(that.version);
		}
		#endregion
	}
}